package com.liuyun.symmetric.pbe;

import lombok.SneakyThrows;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.SecureRandom;

/**
 * <p>
 * Copyright: (C), 2021/1/25 23:21
 * <p>
 * <p>
 * Company Information & Data Security Solutions Co., Ltd.
 *
 * @author LiuYun liujw@idss-cn.com
 * @version 1.0
 */
public class PbeUtil {
    public static final String ALGORITHM = "PBEWITHMD5andDES";

    public static final int ITERATION_COUNT = 100;

    /**
     * 生成随机盐
     *
     * @return 8个字节的盐值
     */
    public static byte[] initSalt() {
        SecureRandom secureRandom = new SecureRandom();
        return secureRandom.generateSeed(8);
    }

    /**
     * 口令转换为密钥
     *
     * @param password
     * @return
     */
    @SneakyThrows
    private static SecretKey toKey(String password) {
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
        return secretKey;
    }

    /**
     * 加密
     *
     * @param data
     * @param password
     * @param salt
     * @return
     */
    @SneakyThrows
    public static byte[] encrypt(byte[] data, String password, byte[] salt) {
        SecretKey secretKey = toKey(password);
        PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
        return cipher.doFinal(data);
    }

    /**
     * 解密
     *
     * @param data
     * @param password
     * @param salt
     * @return
     */
    @SneakyThrows
    public static byte[] decrypt(byte[] data, String password, byte[] salt) {
        SecretKey secretKey = toKey(password);
        PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);
        return cipher.doFinal(data);
    }
}
